package com.breadenglish.cms.api.app.sys.interceptor;

import com.breadenglish.cms.api.app.common.utils.PropertyConfigurerUtils;
import com.breadenglish.cms.api.app.common.utils.StringUtils;
import com.breadenglish.cms.api.app.domain.constants.Constants;
import com.breadenglish.cms.api.app.domain.exception.BusinessException;
import com.breadenglish.cms.api.app.domain.exception.DataAccessException;
import com.breadenglish.cms.api.app.domain.exception.ParameterException;
import com.breadenglish.cms.api.app.domain.model.ResultMessage;
import com.breadenglish.cms.api.app.sys.context.MessageContextHolder;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 控制层异常处理类
 */
@Service("handlerMethodExceptionResolver")
public class HandlerMethodExceptionResolver implements HandlerExceptionResolver {

    private static Logger logger = LoggerFactory.getLogger(HandlerMethodExceptionResolver.class);

    @Override
//    @ResponseBody
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {
        // 异常信息处理
        ResultMessage message;
        if (e instanceof BusinessException) {
            BusinessException be = (BusinessException) e;
            message = buildExceptionJson("业务处理异常", be.getCode(), be.getKeys(), e);
        } else if (e instanceof ParameterException) {
            ParameterException pe = (ParameterException) e;
            message = buildExceptionJson("参数处理异常", pe.getCode(), pe.getKeys(), e);
        } else if (e instanceof DataAccessException) {
            DataAccessException de = (DataAccessException) e;
            message = buildExceptionJson("数据库访问处理异常", de.getCode(), de.getKeys(), e);
        } else {
            message = buildExceptionJson("运行时异常", null, null, e);
            List<String> contents = new ArrayList<String>();
            contents.add("程序运行中出现异常！请重试！");
            contents.add("如重试继续异常！请联系管理员！");
            message.setContent(contents);
        }

        // 项目访问路径
//        String projectPath = PropertyConfigurerUtils.getProperty(Constants.PROJECT_PATH);
        // 判断方法是否带有@ResponseBody注解
        HandlerMethod handlerMethod = (HandlerMethod) o;
        Method method = handlerMethod.getMethod();
        ResponseBody responseBodyAnn = AnnotationUtils.findAnnotation(method, ResponseBody.class);
        if (responseBodyAnn != null) {
            // 设置异常信息对象上下文
            MessageContextHolder.setExceptionJson(message);
//            return new ModelAndView(new RedirectView(projectPath + "/sys/forwardResponseBody.html"));
            return new ModelAndView("forward:/sys/forwardResponseBody.html");//
        }
        // 返回类型为ResponseEntity的异常跳转
        if (method.getReturnType() == ResponseEntity.class) {
            // 设置异常信息对象上下文
            MessageContextHolder.setExceptionJson(message);
//            return new ModelAndView(new RedirectView(projectPath + "/sys/forwardResponseEntity.html"));
            return new ModelAndView("forward:/sys/forwardResponseBody.html");
        }
        // 默认跳转
        return new ModelAndView("error", Constants.ERROR_MESSAGE_NAME, message);
    }

    private ResultMessage buildExceptionJson(String title, String code, List<String[]> keys, Exception e) {
        ResultMessage message = new ResultMessage();
        message.setTitle(title);
        logger.error(title, e);
        // 异常代码不为空，取配置文件中的异常信息
        if (StringUtils.isNotBlank(code)) {
            // 取配置文件中信息
            String msg = PropertyConfigurerUtils.getProperty(code);
            // 信息不为空
            if (StringUtils.isNotBlank(msg)) {
                List<String> contents = new ArrayList<String>();
                // 异常信息中的key值是否为空
                if (CollectionUtils.isNotEmpty(keys)) {
                    for (String[] arrayStr : keys) {
                        String msgText = MessageFormat.format(msg, (Object[]) arrayStr);
                        contents.add(msgText);
                        logger.error(msgText);
                    }
                } else {
                    contents.add(msg);
                    logger.error(msg);
                }
                message.setContent(contents);
            }
        }
        return message;
    }
}
